#ifndef __ABSTRACTFACTORY_H__
#define __ABSTRACTFACTORY_H__


#include <string>
#include <boost/utility.hpp>
#include <memory>
#include <functional>
#include <unordered_map>
#include <iostream>
#include "Any.h"


class AbstractFactory: boost::noncopyable {
public:

    template<typename T, typename... Args>
    static void Register(const std::string& strKey) {
        std::function<T* (Args...)> func = [](Args... args) {
            return new T(args...);
        };
        Register(strKey, func);
    }
    
    template<typename Base, typename Depend, typename... Args>
    static typename std::enable_if<std::is_base_of<Base, Depend>::value>::type
    RegisterBase(const std::string strKey) {
        std::function<Base* (Args...)> func = [](Args... args) {
            return new Depend(args...);
        };
        Register(strKey, func);
    }

    template<typename T, typename... Args>
    static std::shared_ptr<T> getObject(const std::string& strKey, Args... args) {
        T* ptr = Resolve<T*, Args...>(strKey, args...);
        return std::shared_ptr<T>(ptr);
    }


private:
    static void Register(const std::string& strKey, Any constructor) {
        if(s_creatorMap.count(strKey)) {
            throw std::invalid_argument("strKey is already register!!!");
        }
        s_creatorMap.emplace(strKey, constructor);
    }

    template<typename T, typename... Args>
    static T Resolve(const std::string &strKey, Args... args) {
        if(!s_creatorMap.count(strKey)) {
            throw std::invalid_argument("strKey is NOT register!!!");
        }
        Any functionHandler = s_creatorMap[strKey];
        auto func = functionHandler.AnyCast<std::function<T (Args...)>>();
        //NOTE std::forward要配合decltype使用才可以
        return func(std::forward<decltype(args)>(args)...);
    }

private:
    static std::unordered_map<std::string, Any> s_creatorMap;
};

#endif
